#include "stdafx.h"
#include <Packet32.h>
#include <ntddndis.h>
#include <pcap.h>
#include <winsock2.h>
#include <cstring>
#include <stdio.h>
#include "PacketIO.hpp"


#define Max_Num_Adapter 10
char AdapterList[Max_Num_Adapter][1024];

#define IPTOSBUFFERS 12
char* iptos(u_long in)
{
    static char  output[IPTOSBUFFERS][3 * 4 + 3 + 1];
    static short which;
    u_char*      p;

    p     = (u_char*)&in;
    which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
    snprintf(output[which], sizeof(output[which]), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
    return output[which];
}

char* ip6tos(struct sockaddr* sockaddr, char* address, int addrlen)
{
    socklen_t sockaddrlen;

    sockaddrlen = sizeof(struct sockaddr_in6);

    if (getnameinfo(sockaddr, sockaddrlen, address, addrlen, NULL, 0, NI_NUMERICHOST) != 0)
        address = NULL;

    return address;
}

int PacketIO::GetMACAddress(const char* adapter, uint8_t* mac)
{
    LPADAPTER        lpAdapter = 0;
    DWORD            dwErrorCode;
   //char             AdapterName[8192];
   //char *           temp, *temp1;
	int              AdapterNum = 0;
   //ULONG            AdapterLength;
    PPACKET_OID_DATA OidData;
    BOOLEAN          Status;

    lpAdapter = PacketOpenAdapter((char*)adapter);

    if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE))
    {
        dwErrorCode = GetLastError();
		LOG_DEBUG("Unable to open the adapter, Error Code : %lx\n", dwErrorCode);

        return -1;
    }

    //
    // Allocate a buffer to get the MAC adress
    //

    OidData = (PACKET_OID_DATA*)malloc(6 + sizeof(PACKET_OID_DATA));
    if (OidData == NULL)
    {
		LOG_DEBUG("error allocating memory!\n");
        PacketCloseAdapter(lpAdapter);
        return -1;
    }

    //
    // Retrieve the adapter MAC querying the NIC driver
    //

    OidData->Oid = OID_802_3_CURRENT_ADDRESS;

    OidData->Length = 6;
    ZeroMemory(OidData->Data, 6);

    Status = PacketRequest(lpAdapter, FALSE, OidData);
    if (Status)
    {
        mac[0] = (OidData->Data)[0];
        mac[1] = (OidData->Data)[1];
        mac[2] = (OidData->Data)[2];
        mac[3] = (OidData->Data)[3];
        mac[4] = (OidData->Data)[4];
        mac[5] = (OidData->Data)[5];
		LOG_DEBUG("The MAC address of the adapter is %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
               (OidData->Data)[0],
               (OidData->Data)[1],
               (OidData->Data)[2],
               (OidData->Data)[3],
               (OidData->Data)[4],
               (OidData->Data)[5]);
    }
    else
    {
		LOG_DEBUG("error retrieving the MAC address of the adapter!\n");
    }

    free(OidData);
    PacketCloseAdapter(lpAdapter);
    return (0);
}

void PacketIO::DisplayDevices()
{
    pcap_if_t*   alldevs;
    pcap_if_t*   d;
    pcap_addr_t* a;
    int          i = 0;
    char         errbuf[PCAP_ERRBUF_SIZE];
    char         ip6str[128];

    /* Retrieve the device list from the local machine */

    if (pcap_findalldevs(&alldevs, errbuf) == -1)
    {
		LOG_DEBUG("Error in pcap_findalldevs_ex: %s\n", errbuf);
        exit(1);
    }

    /* Print the list */
    for (d = alldevs; d != NULL; d = d->next)
    {
		LOG_DEBUG("%d. %s", ++i, d->name);
        if (d->description)
        {
            LOG_DEBUG(" (%s)\n", d->description);
        }
        else
        {
            LOG_DEBUG(" (No description available)\n");
        }

        for (a = d->addresses; a; a = a->next)
        {
            LOG_DEBUG("\tAddress Family: #%d\n", a->addr->sa_family);

            switch (a->addr->sa_family)
            {
            case AF_INET:
                LOG_DEBUG("\tAddress Family Name: AF_INET\n");
                if (a->addr)
                    LOG_DEBUG("\tAddress: %s\n",
                           iptos(((struct sockaddr_in*)a->addr)->sin_addr.s_addr));
                if (a->netmask)
                    LOG_DEBUG("\tNetmask: %s\n",
                           iptos(((struct sockaddr_in*)a->netmask)->sin_addr.s_addr));
                if (a->broadaddr)
                    LOG_DEBUG("\tBroadcast Address: %s\n",
                           iptos(((struct sockaddr_in*)a->broadaddr)->sin_addr.s_addr));
                if (a->dstaddr)
                    LOG_DEBUG("\tDestination Address: %s\n",
                           iptos(((struct sockaddr_in*)a->dstaddr)->sin_addr.s_addr));
                break;

            case AF_INET6:
                LOG_DEBUG("\tAddress Family Name: AF_INET6\n");
                if (a->addr)
                    LOG_DEBUG("\tAddress: %s\n", ip6tos(a->addr, ip6str, sizeof(ip6str)));
                break;

            default: LOG_DEBUG("\tAddress Family Name: Unknown\n"); break;
            }
        }
    }

    if (i == 0)
    {
        LOG_DEBUG("\nNo interfaces found! Make sure WinPcap is installed.\n");
        return;
    }

    /* We don't need any more the device list. Free it */
    pcap_freealldevs(alldevs);
}

void PacketIO::GetDevice(int interfaceNumber, char* buffer, size_t buffer_size)
{
    pcap_if_t* alldevs;
    pcap_if_t* d;
    int        i = 0;
    char       errbuf[PCAP_ERRBUF_SIZE];

    /* Retrieve the device list from the local machine */

    if (pcap_findalldevs(&alldevs, errbuf) == -1)
    {
        LOG_DEBUG("Error in pcap_findalldevs_ex: %s\n", errbuf);
        exit(1);
    }

    /* Print the list */
    d = alldevs;
    for (int i = 0; i < interfaceNumber - 1; i++)
    {
        if (d)
        {
            d = d->next;
        }
    }
    buffer[0] = 0;
    if(d)
    {
        strncpy_s(buffer,buffer_size, d->name, buffer_size);
    }

    /* We don't need any more the device list. Free it */
    pcap_freealldevs(alldevs);
}

PacketIO::PacketIO(const char* name)
    : CaptureDevice(name)
{
    char errbuf[PCAP_ERRBUF_SIZE];

    /* Open the device */
    /* Open the adapter */
    if ((adhandle =
             pcap_open_live(CaptureDevice, // name of the device
                            65536,         // portion of the packet to capture.
                            // 65536 grants that the whole packet will be captured on all the MACs.
                            1,     // promiscuous mode (nonzero means promiscuous)
                            1,     // read timeout
                            errbuf // error buffer
                            )) == NULL)
    {
        LOG_DEBUG(
                "\nUnable to open the adapter. %s is not supported by WinPcap\n",
                CaptureDevice);
    }
}

//============================================================================
//
//============================================================================

void PacketIO::Start(pcap_handler handler)
{
    /* start the capture */
    pcap_loop(adhandle, 0, handler, NULL);
}

//============================================================================
//
//============================================================================

void PacketIO::Stop()
{
    pcap_close(adhandle);
}

//============================================================================
//
//============================================================================

bool PacketIO::TxData(void* packet, size_t length)
{
   // LOG_DEBUG( "Ethernet Tx: size = %llu\n",length);
	if (length>0x07FFFFFFFi64)
	{
		LOG_DEBUG("\nError send size\r\n");
		return false;
	}
    if (pcap_sendpacket(adhandle, (u_char*)packet, (int)length) != 0)
    {
        LOG_DEBUG("\nError sending the packet: %s\n", pcap_geterr(adhandle));
		return false;
    }
	return true;
}